package com.nb.provider.auth;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.nb.provider.Result;
import com.nb.provider.ResultEnum;
import com.nb.sdk.util.Md5Util;
import lombok.extern.slf4j.Slf4j;
//import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.*;

/**
 *  验签
 */
@Slf4j
@Component
public class SignVerifyInterceptor extends HandlerInterceptorAdapter {

//    @Autowired
//    private ClientAppProperties clientAppProperties;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        CheckSign checkSign = handlerMethod.getMethodAnnotation(CheckSign.class);
        if (Objects.isNull(checkSign)) {
            return true;
        }

        MyRequestWrapper requestWrapper = new MyRequestWrapper(request);
        String appId = requestWrapper.getHeader(SignConstant.APP_ID);
        String sign = requestWrapper.getHeader(SignConstant.SIGNATURE_STR);
        String timestamp = requestWrapper.getHeader(SignConstant.TIME_STAMP);
        log.info("signVerify request param,appId:{},sign:{},timestamp:{}", appId, sign,timestamp);
        if (StrUtil.isBlank(appId)) {
            log.warn("signVerify: appId is blank");
            response(response, Result.error(ResultEnum.PARAM_ERROR.getCode(), SignConstant.LOST_PARAM_APPID));
            return false;
        }
        String appSecret = ClientAppProperties.appSecret;
        if(StrUtil.isBlank(appSecret)){
            log.warn("signVerify:appSecret is blank,appId not exist ");
            response(response, Result.error(ResultEnum.PARAM_ERROR.getCode(), SignConstant.NO_EXIST_APPID));
            return false;
        }
        if (StrUtil.isBlank(sign)) {
            log.warn("signVerify:sign is blank ");
            response(response, Result.error(ResultEnum.PARAM_ERROR.getCode(), SignConstant.LOST_PARAM_SIGN));
            return false;
        }
        if (StrUtil.isNotBlank(timestamp)) {
            DateTime reqDateTime = null;
            try {
                reqDateTime = DateUtil.parse(timestamp, DatePattern.NORM_DATETIME_PATTERN);
                if (signIsTimeout(reqDateTime)) {
                    //超时
                    log.warn("signverify ,sign过期,超时时间(秒数):{}", SignConstant.expireTimeSeconds);
                    response(response,Result.error(ResultEnum.PARAM_ERROR.getCode(), SignConstant.SIGN_TIMEOUT));
                    return false;
                }
            } catch (Exception e) {
                log.warn("signverify ,解析timestamp失败,入参 timestamp:{}",timestamp);
                response(response, Result.error(ResultEnum.PARAM_ERROR.getCode(), SignConstant.TIMESTAMP_FMT_ERROR));
                return false;
            }
        }

        if("POST".equals(request.getMethod())){
            String bodyJson = new String(requestWrapper.getBody(), Charset.forName("UTF-8"));
            log.info("signVerifyInterceptor bodyJson:{}",bodyJson);
            String signStr = appId + appSecret + bodyJson ;
            System.err.println("验证签名："+signStr);
            if(StrUtil.isNotBlank(timestamp)){
                signStr+=timestamp;
            }
            String sign2 = Md5Util.getMd5(signStr).toUpperCase();
            log.info("signverify get sign >>>>>>:{}", signStr);
            if (!StrUtil.equalsIgnoreCase(sign2, sign)) {
                response(response, Result.error(ResultEnum.SIGN_AUTH_FAIL));
                return false;
            }
        }
        if("GET".equals(request.getMethod())){
            String signStr = appId+appSecret+getGetSignString(request);
            String sign2 = Md5Util.getMd5(signStr).toUpperCase();
            log.info("signverify get sign >>>>>>:{}" + signStr);
            if (!StrUtil.equalsIgnoreCase(sign2, sign)) {
                response(response, Result.error(ResultEnum.SIGN_AUTH_FAIL));
                return false;
            }
        }
        return true;
    }

    private boolean signIsTimeout(DateTime reqDateTime) {
        return DateUtil.between(reqDateTime.toJdkDate(), new Date(), DateUnit.SECOND) > SignConstant.expireTimeSeconds;
    }


    public String getGetSignString(HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        String queryString = request.getQueryString();
        if (StrUtil.isBlank(queryString)) {
            return requestURI;
        } else {
            return StrUtil.join(requestURI,"?",queryString);
        }
    }

//    private String getAppSecret(String appId) {
//        return ClientAppProperties.getApps().get(appId);
//    }


    public static void response(HttpServletResponse response, Result<?> result) throws IOException {
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");
        response.getWriter().write(JSONUtil.toJsonStr(result));
        response.getWriter().flush();
    }


}







//    public static String getSortedString(HttpServletRequest request) {
//        Map<String, String[]> parameterMap = request.getParameterMap();
//
//        SortedMap<String, String[]> sortMap = new TreeMap<>();
//        StringBuffer sbf = new StringBuffer();
//
//        if(MapUtil.isNotEmpty(parameterMap)){
//            Iterator<Map.Entry<String, String[]>> iter = parameterMap.entrySet().iterator();
//            while(iter.hasNext()){
//                Map.Entry<String, String[]> entry = iter.next();
//                String key = entry.getKey();
//                String[] value = entry.getValue();
//                if (StringUtils.equalsAny(key,SignConstant.APP_ID,SignConstant.SIGNATURE_STR)) {
//                    continue;
//                }
//                sortMap.put(key, value);
//            }
//
//        }
//        Iterator<Map.Entry<String, String[]>> iter = sortMap.entrySet().iterator();
//        while (iter.hasNext()) {
//            Map.Entry<String, String[]> entry = iter.next();
//            String key = entry.getKey();
//            String[] value = entry.getValue();
//            sbf.append(key + "=" + value + "&");
//        }
//        String sbfString = sbf.toString();
//        System.out.println("排序后的字符串：" + sbfString.substring(0, sbfString.length() - 1));
//        return sbfString.substring(0, sbfString.length() - 1);
//    }